package com.randi.file.utils;

import com.randi.common.config.AppConfig;
import com.randi.common.enums.ResultCode;
import com.randi.common.exception.ServiceException;
import com.randi.common.utils.StringUtils;
import org.apache.commons.io.IOUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.*;

/**
 * 文件上传工具类
 *
 * @author randi
 * @date 2020-07-21 15:01:07
 * @since 1.0.0
 */
public class UploadFileUtils extends SysFileUtils {

    /**
     * 默认大小 10M
     */
    public static Long DEFAULT_MAX_SIZE;

    /**
     * 文件保存目录 [默认路径]
     */
    private static String FILE_SAVE_FOLDER;

    @Resource
    private void init(AppConfig.FileConfig.UploadFileConfig uploadFileConfig) {
        DEFAULT_MAX_SIZE = uploadFileConfig.getMaxSize();
        FILE_SAVE_FOLDER = uploadFileConfig.getSavePathSuffix();
    }

    /**
     * 获取文件保存路径
     *
     * @param fileHash 文件哈希
     * @return 文件保存路径
     */
    public static String getSaveFilePath(String fileHash) {
        if (StringUtils.isEmpty(fileHash)) {
            return null;
        }
        return StringUtils.format("{}{}{}", FILE_SAVE_FOLDER, SEPARATOR, fileHash);
    }

    /**
     * 获取文件保存基本路径 [绝对路径]
     *
     * @param fileHash 文件哈希
     * @return 文件保存路径
     */
    public static String getSaveFileBasePath(String fileHash) {
        String fileSavePath = getSaveFilePath(fileHash);
        return getBasePath(fileSavePath);
    }

    /**
     * 获取上传保存文件对象
     *
     * @param fileHash 文件哈希
     * @return 文件对象
     */
    public static File getSaveFile(String fileHash) {
        String savePath = getSaveFilePath(fileHash);
        return getFile(savePath);
    }

    /**
     * 判断文件是否上传
     *
     * @param fileHash 文件哈希
     * @return 是否存在
     */
    public static boolean hasBeenFileUploaded(String fileHash) {
        String fileSavePath = getSaveFilePath(fileHash);
        return fileExist(fileSavePath);
    }

    /**
     * 上传前置校验
     *
     * @param file 文件
     */
    public static void uploadAfterCheck(MultipartFile file) {
        long size = file.getSize();
        if (size > DEFAULT_MAX_SIZE) {
            throw new ServiceException(ResultCode.FILE_UPLOAD_FAIL_SIZE);
        }
    }

    /**
     * 文件上传
     *
     * @param bytes    文件字节
     * @param filePath 文件路径
     * @return 是否成功
     */
    public static boolean upload(byte[] bytes, String filePath) {
        FileOutputStream fileOutputStream = null;
        try {
            fileOutputStream = new FileOutputStream(filePath);
            fileOutputStream.write(bytes);
            return true;
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        } finally {
            IOUtils.closeQuietly(fileOutputStream);
        }
    }

    /**
     * 根据文件哈希上传文件 [默认路径]
     *
     * @param file     文件
     * @param fileHash 文件哈希
     * @return 是否成功
     */
    public static boolean simpleUpload(MultipartFile file, String fileHash) throws IOException {
        uploadAfterCheck(file);
        boolean status = hasBeenFileUploaded(fileHash);
        if (status) {
            return true;
        }

        // 获取文件路径
        String basePath = getSaveFileBasePath(fileHash);
        createFolder(FILE_SAVE_FOLDER);
        return upload(file.getBytes(), basePath);
    }

    /*
     * --------------------------------------------------------------------------
     * |                             自定义路径上传                                |
     * --------------------------------------------------------------------------
     */

    /**
     * 获取文件路径
     *
     * @param pathName 路径
     * @param fileHash 文件哈希
     * @return 文件路径
     */
    public static String getSaveFilePath(String pathName, String fileHash) {
        if (StringUtils.isEmpty(pathName)) {
            return getSaveFilePath(fileHash);
        }
        return StringUtils.format("{}{}{}", pathName, SEPARATOR, fileHash);
    }

    /**
     * 获取文件对象
     *
     * @param pathName 路径
     * @param fileHash 文件哈希
     * @return 文件路径
     */
    public static File getSaveFile(String pathName, String fileHash) {
        String saveFilePath = getSaveFilePath(pathName, fileHash);
        return getFile(saveFilePath);
    }

    /**
     * 判断文件是否上传
     *
     * @param pathName 文件路径
     * @param fileHash 文件哈希
     * @return 是否存在
     */
    public static boolean hasBeenFileUploaded(String pathName, String fileHash) {
        String fileSavePath = getSaveFilePath(pathName, fileHash);
        return fileExist(fileSavePath);
    }

    /**
     * 指定路径上传文件
     *
     * @param file     文件
     * @param pathName 文件路径
     * @param fileHash 文件哈希
     * @return 成功或失败
     */
    public static boolean simpleUploadByFolder(MultipartFile file, String pathName, String fileHash) throws IOException {
        if (StringUtils.isEmpty(pathName)) {
            return simpleUpload(file, fileHash);
        }
        boolean isExist = hasBeenFileUploaded(pathName, fileHash);
        if (isExist) {
            return true;
        }
        uploadAfterCheck(file);
        String basePath = getBasePath(getSaveFilePath(pathName, fileHash));
        createFolder(pathName);
        return upload(file.getBytes(), basePath);
    }
}
